/**
  ******************************************************************************
  * @file    sccb.c
  * @author  W. Boerendans
  * @version V1.0.0
  * @date    02-february-2013
  * @brief   SCCB
  *         
  * <h2><center>&copy; COPYRIGHT 2013 W. Boerendans</center></h2>
  ******************************************************************************  
  */ 
	
/* Private includes ----------------------------------------------------------*/
#include "dcmi.h"

/* Private declarations ------------------------------------------------------*/
image_t *pImg;
/* Private prototypes --------------------------------------------------------*/
/**
 * @name dcmi_io_init
 * @brief Configuration of IO
 */
void dcmiIoInit(void);

/* Functions -----------------------------------------------------------------*/
void dcmiInit(image_t *img)
{
	DCMI_InitTypeDef DCMI_InitStructure;
	DMA_InitTypeDef  DMA_InitStructure;
	
	if(img == NULL)
		return;
	if(img < (image_t*)0x20000000)  //not a valid sram address
		return;
	if(img >= (image_t*)0x20020000) //not a valid sram address
		return;
		
	// Copy address
	pImg = img;
	
	// Disable DCMI
	DCMI_Cmd(DISABLE);
	
	// Init DCMI IO 
	dcmiIoInit();
	
	// Clocks */
	RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_DCMI, ENABLE);
	
	// VSYNC = Frame
	// HSYNC = line
	
	// DCMI Controller config 
	DCMI_InitStructure.DCMI_CaptureMode = DCMI_CaptureMode_SnapShot;//DCMI_CaptureMode_Continuous;//DCMI_CaptureMode_SnapShot;
	DCMI_InitStructure.DCMI_SynchroMode = DCMI_SynchroMode_Hardware;
	DCMI_InitStructure.DCMI_PCKPolarity = DCMI_PCKPolarity_Rising;
	DCMI_InitStructure.DCMI_VSPolarity = DCMI_VSPolarity_High;
	DCMI_InitStructure.DCMI_HSPolarity = DCMI_HSPolarity_Low; //DCMI_HSPolarity_High; //;
	DCMI_InitStructure.DCMI_CaptureRate = DCMI_CaptureRate_All_Frame;//DCMI_CaptureRate_All_Frame;//DCMI_CaptureRate_1of4_Frame; //DCMI_CaptureRate_All_Frame;
	DCMI_InitStructure.DCMI_ExtendedDataMode = DCMI_ExtendedDataMode_8b;
	DCMI_Init(&DCMI_InitStructure);

	// DMA2 Stream 1 config
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
	DMA_DeInit(DMA2_Stream1);

	/*DMA_StructInit(&DMA_InitStructure);
	DMA_InitStructure.DMA_Channel = DMA_Channel_1;
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // DMA_Mode_Normal;
	DMA_InitStructure.DMA_Priority = DMA_Priority_Low;

	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(DCMI->DR);
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
	DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

	DMA_InitStructure.DMA_Memory0BaseAddr = NULL; // No buffer yet
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
	DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;*/

	DMA_InitStructure.DMA_Channel = DMA_Channel_1;  
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA_Mode_Normal; //DMA_Mode_Circular
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;

	//DCIM collects 4 bytes (WORD) before calling a DMA transfer.
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(DCMI->DR);
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
	DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

	DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)(img->data);
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_BufferSize = (IMG_MEMORY);
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;

	DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;         
	DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
	DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;

	DMA_Init(DMA2_Stream1, &DMA_InitStructure);

	// DMA double buffer mode config
	/*
	DMA_DoubleBufferModeConfig(DMA2_Stream1, NULL, DMA_Memory_0);
	DMA_DoubleBufferModeCmd(DMA2_Stream1, ENABLE);

	DMA_SetCurrDataCounter(DMA2_Stream1, (IMG_HEIGHT*IMG_WIDTH)/4);
	DMA_MemoryTargetConfig(DMA2_Stream1, (uint32_t)(image.data),DMA_Memory_0);*/

	//DMA_MemoryTargetConfig(DMA2_Stream1, (uint32_t)(image[0].data),DMA_Memory_0);
	//DMA_MemoryTargetConfig(DMA2_Stream1, (uint32_t)(image[1].data),DMA_Memory_1);

	//DCMI_ClearFlag(DCMI_FLAG_OVFRI);
	DCMI_ClearFlag(DCMI_FLAG_FRAMERI);
	//DCMI_ClearFlag(DCMI_IT_ERR);
	//DCMI_ClearFlag(DCMI_IT_VSYNC);
	//DCMI_ClearFlag(DCMI_IT_LINE);

	//DCMI_ITConfig(DCMI_IT_OVF, ENABLE);
	DCMI_ITConfig(DCMI_IT_FRAME, ENABLE);
	//DCMI_ITConfig(DCMI_IT_ERR, ENABLE);
	//DCMI_ITConfig(DCMI_IT_VSYNC, ENABLE);
	//DCMI_ITConfig(DCMI_IT_LINE, ENABLE);

	NVIC_EnableIRQ(DCMI_IRQn);

	DMA_Cmd(DMA2_Stream1, ENABLE);

	DCMI_Cmd(ENABLE);
}
void dcmiIoInit(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	// Clocks
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);

	// Alternative pin configuration
	GPIO_PinAFConfig(GPIOA, (GPIO_PinSource4), GPIO_AF_DCMI);
	GPIO_PinAFConfig(GPIOA, (GPIO_PinSource6), GPIO_AF_DCMI);

	GPIO_PinAFConfig(GPIOB, (GPIO_PinSource5), GPIO_AF_DCMI);
	GPIO_PinAFConfig(GPIOB, (GPIO_PinSource6), GPIO_AF_DCMI);
	GPIO_PinAFConfig(GPIOB, (GPIO_PinSource7), GPIO_AF_DCMI);
	GPIO_PinAFConfig(GPIOB, (GPIO_PinSource8), GPIO_AF_DCMI);

	GPIO_PinAFConfig(GPIOC, (GPIO_PinSource6), GPIO_AF_DCMI);
	GPIO_PinAFConfig(GPIOC, (GPIO_PinSource7), GPIO_AF_DCMI);
	GPIO_PinAFConfig(GPIOC, (GPIO_PinSource8), GPIO_AF_DCMI);
	GPIO_PinAFConfig(GPIOC, (GPIO_PinSource10), GPIO_AF_DCMI);
	GPIO_PinAFConfig(GPIOC, (GPIO_PinSource11), GPIO_AF_DCMI);
	GPIO_PinAFConfig(GPIOC, (GPIO_PinSource12), GPIO_AF_DCMI);

	GPIO_PinAFConfig(GPIOD, (GPIO_PinSource2), GPIO_AF_DCMI);

	GPIO_PinAFConfig(GPIOE, (GPIO_PinSource1), GPIO_AF_DCMI);
	GPIO_PinAFConfig(GPIOE, (GPIO_PinSource6), GPIO_AF_DCMI);

	// DCMI Pinconfig
	GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_4 | GPIO_Pin_6);
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8);
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12);
	GPIO_Init(GPIOC, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_2);
	GPIO_Init(GPIOD, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_1 | GPIO_Pin_6);
	GPIO_Init(GPIOE, &GPIO_InitStructure);
}
void DCMI_IRQHandler(void)
{
  uint16_t misr = DCMI->MISR;
	//static uint8_t count = 0, fail = 1;
	
  /*if(misr & DCMI_FLAG_OVFRI)
  {
    DCMI_ClearFlag(DCMI_FLAG_OVFRI);
  }
	if(misr & DCMI_FLAG_HSYNC) //HSYNC flag mask
	{
		DCMI_ClearFlag(DCMI_FLAG_HSYNC);
	}
	if(misr & DCMI_FLAG_VSYNC) //VSYNC flag mask
	{
		DCMI_ClearFlag(DCMI_FLAG_VSYNC);
	}
	if(misr & DCMI_FLAG_ERRRI) //Synchronization error Raw flag mask
	{
		DCMI_ClearFlag(DCMI_FLAG_ERRRI);
	}
	if(misr & DCMI_FLAG_OVFRI) //Overflow Raw flag mask
	{
		DCMI_ClearFlag(DCMI_FLAG_OVFRI);
	}
	if(misr & DCMI_FLAG_LINERI) //Line
	{
		DCMI_ClearFlag(DCMI_FLAG_LINERI);
	}
	*/
	if(misr & DCMI_FLAG_FRAMEMI) //frame complete
	{
		//if(DMA2_Stream1->NDTR == IMG_MEMORY)
		
		/*if(DMA2_Stream1->NDTR == IMG_MEMORY || DMA2_Stream1->NDTR == (IMG_MEMORY - (pImg->pixels/2)))
		{
			GPIOD->ODR |= (1<<12);
			if(fail == 0){
				GPIOD->ODR &= ~(1<<14);
			}				
			else	
				fail--;
		}
		else 
		{
			GPIOD->ODR &= ~(1<<12);
			if(count >= 1){
				GPIOD->ODR |= (1<<14);
				fail = 1;
			}
			else
				count++;
			//RESET DMA, return to start address
			//DCMI_Cmd(DISABLE); 
			//DMA_Cmd(DMA2_Stream1, DISABLE);		
			//DMA_Cmd(DMA2_Stream1, ENABLE);
			//DCMI_Cmd(ENABLE); 
			//DCMI_CaptureCmd(ENABLE);

		} */
		
		// Save check value
		pImg->check = DMA2_Stream1->NDTR;
		
		//RESET DMA, return to start address
		//DCMI_Cmd(DISABLE); 
		//DMA_Cmd(DMA2_Stream1, DISABLE);		
		//DMA_Cmd(DMA2_Stream1, ENABLE);
		//DCMI_Cmd(ENABLE); 
		//DCMI_CaptureCmd(ENABLE);

		//GPIOD->ODR ^= (1<<13); //toggle orange led
		DCMI_ClearFlag(DCMI_FLAG_FRAMEMI);
	}
}
